package nd.android.am;

import java.util.HashMap;

import nd.android.am.Adapter.Account;
import nd.android.am.Adapter.Config;
import nd.android.am.Adapter.User;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

public class AccountProvider extends ContentProvider {
    private static final String TAG = "UserProvider";

    public static final String DATABASE_NAME = "account_manager.db";
    public static final int DATABASE_VERSION = 8;
    private static final String ACCOUNT_TABLE_NAME = "accounts";
    private static final String USER_TABLE_NAME = "users";
    private static final String CONFIG_TABLE_NAME = "configs";
    
    private static final int ACCOUNTS = 1;
    private static final int ACCOUNT_ID = 2;
    private static final int USERS = 3;
    private static final int USER_ID = 4;
    private static final int CONFIGS = 5;
    private static final int CONFIG_ID = 6;
    
    private static final UriMatcher uriMatcher;
    private static HashMap<String, String> accountProjectionMap;
    private static HashMap<String, String> userProjectionMap;
    private static HashMap<String, String> configProjectionMap;
    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(Adapter.AUTHORITY, "accounts", ACCOUNTS);
        uriMatcher.addURI(Adapter.AUTHORITY, "accounts/#", ACCOUNT_ID);
        uriMatcher.addURI(Adapter.AUTHORITY, "users", USERS);
        uriMatcher.addURI(Adapter.AUTHORITY, "users/#", USER_ID);
        uriMatcher.addURI(Adapter.AUTHORITY, "configs", CONFIGS);
        uriMatcher.addURI(Adapter.AUTHORITY, "configs/#", CONFIG_ID);

        accountProjectionMap = new HashMap<String, String>();
        for (int i = 0; i < Account.PROJECTION.length; i++) {
        	accountProjectionMap.put(Account.PROJECTION[i], Account.PROJECTION[i]);
		}
        
        userProjectionMap = new HashMap<String, String>();
        for (int i = 0; i < User.PROJECTION.length; i++) {
        	userProjectionMap.put(User.PROJECTION[i], User.PROJECTION[i]);
		}
        
        configProjectionMap = new HashMap<String, String>();
        for (int i = 0; i < Config.PROJECTION.length; i++) {
        	configProjectionMap.put(Config.PROJECTION[i], Config.PROJECTION[i]);
		}
    }

    private DatabaseHelper dbHelper;

	@Override
	public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
        
        case ACCOUNTS:
            return Account.CONTENT_TYPE;
        case ACCOUNT_ID:
            return Account.CONTENT_ITEM_TYPE;

        case USERS:
            return User.CONTENT_TYPE;
        case USER_ID:
            return User.CONTENT_ITEM_TYPE;
            
        case CONFIGS:
            return Config.CONTENT_TYPE;
        case CONFIG_ID:
            return Config.CONTENT_ITEM_TYPE;
            
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

        int type = uriMatcher.match(uri);
        String defaultOrderBy = null;
        switch (type) {
		case ACCOUNT_ID:
            qb.appendWhere(Account._ID + "=" + uri.getPathSegments().get(1));
		case ACCOUNTS:
            qb.setTables(ACCOUNT_TABLE_NAME);
            qb.setProjectionMap(accountProjectionMap);
            defaultOrderBy = Account.DEFAULT_SORT_ORDER;
            break;
		case CONFIG_ID:
            qb.appendWhere(Config.NAME + "=" + uri.getPathSegments().get(1));
		case CONFIGS:
            qb.setTables(CONFIG_TABLE_NAME);
            qb.setProjectionMap(configProjectionMap);
            defaultOrderBy = Config.DEFAULT_SORT_ORDER;
            break;
		case USER_ID:
            qb.appendWhere(User._ID + "=" + uri.getPathSegments().get(1));
		case USERS:
            qb.setTables(USER_TABLE_NAME);
            qb.setProjectionMap(userProjectionMap);
            defaultOrderBy = User.DEFAULT_SORT_ORDER;
			break;
		default:	
            throw new IllegalArgumentException("Unknown URI " + uri);
		}

        String orderBy = sortOrder;
        if (TextUtils.isEmpty(sortOrder)) {
            orderBy = defaultOrderBy;
        }

        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);

        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
	}

	@Override
	public Uri insert(Uri uri, ContentValues initialValues) {
        ContentValues values;
        if (initialValues != null) {
            values = new ContentValues(initialValues);
        } else {
            values = new ContentValues();
        }
        
		int type = uriMatcher.match(uri);
		Uri nodeUri = null;
		if (type == CONFIGS){
	        if (values.containsKey(Config.NAME) == false) {
	            throw new SQLException("Failed to insert, NAME field must been setted. ");
	        }
	        SQLiteDatabase db = dbHelper.getWritableDatabase();
	        long rowId = db.insert(CONFIG_TABLE_NAME, Config.NAME, values);
	        if (rowId > 0)
	            nodeUri = ContentUris.withAppendedId(Config.CONTENT_URI, rowId);
		} else if (type == USERS) {
	        if (values.containsKey(User.NAME) == false) {
	            throw new SQLException("Failed to insert, NAME field must been setted. ");
	        }
	        SQLiteDatabase db = dbHelper.getWritableDatabase();
	        long rowId = db.insert(ACCOUNT_TABLE_NAME, Account.PURPOSE, values);
	        if (rowId > 0)
	            nodeUri = ContentUris.withAppendedId(Account.CONTENT_URI, rowId);
		} else if (type == ACCOUNTS) {
	        if (values.containsKey(Account.AMOUNT) == false) {
	            throw new SQLException("Failed to insert, AMOUNT field must been setted. ");
	        }
	        if (values.containsKey(Account.PURPOSE) == false) {
	            throw new SQLException("Failed to insert, PURPOSE field must been setted. ");
	        }
	        if (values.containsKey(Account.PAYER) == false) {
	            throw new SQLException("Failed to insert, PAYER field must been setted. ");
	        }
	        if (values.containsKey(Account.OCCUR_DATE) == false) {
	            throw new SQLException("Failed to insert, OCCUR_DATE field must been setted. ");
	        }
	        if (values.containsKey(Account.UPDATE_DATE) == false) {
	        	values.put(Account.UPDATE_DATE, System.currentTimeMillis());
	        }
	        SQLiteDatabase db = dbHelper.getWritableDatabase();
	        long rowId = db.insert(ACCOUNT_TABLE_NAME, Account.PURPOSE, values);
	        if (rowId > 0)
	            nodeUri = ContentUris.withAppendedId(Account.CONTENT_URI, rowId);
        } else {
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        if (nodeUri != null) {
            getContext().getContentResolver().notifyChange(nodeUri, null);
            return nodeUri;
        }

        throw new SQLException("Failed to insert row into " + uri);
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int count;
        switch (uriMatcher.match(uri)) {
        
        case ACCOUNTS:
            count = db.delete(ACCOUNT_TABLE_NAME, selection, selectionArgs);
            break;
        case ACCOUNT_ID:
            String accountId = uri.getPathSegments().get(1);
            count = db.delete(ACCOUNT_TABLE_NAME, Account._ID + "=" + accountId
                    + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
            break;

        case USERS:
            count = db.delete(USER_TABLE_NAME, selection, selectionArgs);
            break;
        case USER_ID:
            String userId = uri.getPathSegments().get(1);
            count = db.delete(USER_TABLE_NAME, User._ID + "=" + userId
                    + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
            break;
            
        case CONFIGS:
            count = db.delete(CONFIG_TABLE_NAME, selection, selectionArgs);
            break;
        case CONFIG_ID:
            String configId = uri.getPathSegments().get(1);
            count = db.delete(CONFIG_TABLE_NAME, Config.NAME + "=" + configId
                    + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
            break;
            
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return count;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int count;
        switch (uriMatcher.match(uri)) {
        
        case ACCOUNTS:
            count = db.update(ACCOUNT_TABLE_NAME, values, selection, selectionArgs);
            break;
        case ACCOUNT_ID:
            String accountId = uri.getPathSegments().get(1);
            count = db.update(ACCOUNT_TABLE_NAME, values, Account._ID + "=" + accountId
                    + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
            break;
            
        case USERS:
            count = db.update(USER_TABLE_NAME, values, selection, selectionArgs);
            break;
        case USER_ID:
            String userId = uri.getPathSegments().get(1);
            count = db.update(USER_TABLE_NAME, values, User._ID + "=" + userId
                    + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
            break;

        case CONFIGS:
            count = db.update(CONFIG_TABLE_NAME, values, selection, selectionArgs);
            break;
        case CONFIG_ID:
            String configId = uri.getPathSegments().get(1);
            count = db.update(CONFIG_TABLE_NAME, values, Config.NAME + "=" + configId
                    + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
            break;

        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return count;
	}

	@Override
	public boolean onCreate() {
		dbHelper = new DatabaseHelper(getContext());
		return true;
	}

    private static class DatabaseHelper extends SQLiteOpenHelper {

		DatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
//			db.isReadOnly();
			db.execSQL("CREATE TABLE " + ACCOUNT_TABLE_NAME + " ("
					+ Account._ID + " INTEGER PRIMARY KEY,"
					+ Account.OCCUR_DATE + " TEXT NOT NULL,"
					+ Account.PURPOSE + " TEXT NOT NULL,"
					+ Account.AMOUNT + " INTEGER NOT NULL,"
					+ Account.PAYER + " TEXT NOT NULL,"
					+ Account.USERS + " TEXT NOT NULL,"
					+ Account.DESC + " TEXT ," 
					+ Account.UPDATE_DATE + " INTEGER ,"
					+ Account.STATUS + " INTEGER DEFAULT 0);");
			db.execSQL("insert into " + ACCOUNT_TABLE_NAME + " (occured,purpose,amount,payer,users) values ('2009-03-11', '晚餐', 2345, '我', '我,你');");
			db.execSQL("insert into " + ACCOUNT_TABLE_NAME + " (occured,purpose,amount,payer,users) values ('2009-03-12', '午餐', 1234, '你', '我,你');");
			db.execSQL("insert into " + ACCOUNT_TABLE_NAME + " (occured,purpose,amount,payer,users) values ('2009-03-12', 'Food', 20000, '你', '我,你');");
			
			db.execSQL("CREATE TABLE " + USER_TABLE_NAME + " (" + User._ID
					+ " INTEGER PRIMARY KEY," + User.NAME + " TEXT NOT NULL"
					+ ");");
			db.execSQL("insert into " + USER_TABLE_NAME + " (_ID,NAME) values (1, '我');");
			db.execSQL("insert into " + USER_TABLE_NAME + " (_ID,NAME) values (2, '你');");
			
			db.execSQL("CREATE TABLE " + CONFIG_TABLE_NAME + " (" 
					+ Config.NAME + " TEXT PRIMARY KEY," 
					+ Config.VALUE + " TEXT"
					+ ");");
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
					+ newVersion + ", which will destroy all old data");
			db.execSQL("DROP TABLE IF EXISTS " + ACCOUNT_TABLE_NAME);
			db.execSQL("DROP TABLE IF EXISTS " + USER_TABLE_NAME);
			db.execSQL("DROP TABLE IF EXISTS " + CONFIG_TABLE_NAME);
			onCreate(db);
		}
	}
}
